48  创建序列和数据框

48.1 引言 Pandas数据结构在金融分析中的核心地位

Pandas是Python数据分析的核心库,建立在NumPy之上,提供了两种专为数据分析和处理设计的数据结构:

理论背景:从NumPy到Pandas的演进

NumPy数组提供了高效的数值计算能力,但在数据分析中存在三个关键限制: 1. 缺乏标签:NumPy数组只能通过整数位置访问,无法使用有意义的标签(如股票代码、日期) 2. 数据类型单一:NumPy数组的所有元素必须是相同类型 3. 缺失值处理:NumPy使用NaN表示缺失值,但处理不够灵活

Pandas通过Series和DataFrame这两种数据结构完美解决了这些问题,使其成为金融数据分析的理想工具。

Pandas两种核心数据结构:

特性 Series DataFrame
维度 一维 二维
类比 带标签的数组 带标签的表格/Excel工作表
索引 必须有索引 必须有行索引,列名是另一种索引
金融应用 单只股票的价格序列 多只股票的多指标数据表

48.2 创建Series对象

Series是Pandas的一维数据结构,可以理解为”带标签的数组”。在金融应用中,Series非常适合存储单只股票的价格序列、单只股票的交易量序列、或某一天的多个股票价格等一维数据。

平台任务解答代码

以下代码与教学平台任务要求完全一致:

列表 48.1
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
#任务一
import numpy as np
import pandas as pd  # 导入Pandas数据分析库

value_guotai = np.array([1.5284,1.4596,1.3745,1.4034,1.3935,1.39,1.412,1.4164]) #国泰金鑫股票基金2024年8月1日至8日净值数据的数组
date = np.array(["2024-08-01","2024-08-02","2024-08-05","2024-08-06","2024-08-07","2024-08-08","2024-08-09","2024-08-12"]) #交易日数组

series_guotai = pd.Series(data=value_guotai,index=date) #创建序列
print(type(series_guotai))  #查看变量的数据结构

data=[1.4596,1.001,0.897,2.051,1.7385];index=["国泰金鑫","中海医疗","华夏优势","富国城镇","上投摩根"] #创建8月2日基金净值的数组

value_0403 = pd.Series(data,index)  # 创建Series序列value_0403
print(type(value_0403))  # 输出数据类型


#任务二
import numpy as np
import pandas as pd  # 导入Pandas数据分析库

date = np.array(["2024-08-01","2024-08-02","2024-08-05","2024-08-06","2024-08-07","2024-08-08","2024-08-09","2024-08-12"]) #交易日数组

name = np.array(["国泰金鑫","中海医疗","华夏优势","富国城镇","上投摩根"])  #基金名称的数组并且用基金简称

data_3fund_array = np.array([[1.01,0.8918,2.038],[0.995,0.8833,2.025],[1.002,0.8735,2.032]]) #3只基金在2024年8月8日至12日净值的数组

data_3fund = pd.DataFrame(data=data_3fund_array,index=date[5:],columns=name[1:4]) #转成一个数据框

print(type(data_3fund))  # 输出数据类型

#任务三
import numpy as np
import pandas as pd  # 导入Pandas数据分析库

date = np.array(["2024-08-01","2024-08-02","2024-08-05","2024-08-06","2024-08-07","2024-08-08","2024-08-09","2024-08-12"]) #交易日数组

name = np.array(["国泰金鑫","中海医疗","华夏优势","富国城镇","上投摩根"])  # 创建NumPy数组name

# 创建NumPy数组value_total
value_total = np.array([[1.5284,0.991,0.9122,2.069,1.7742],[1.4596,1.001,0.897,2.051,1.7385],[1.3745,1,0.8786,2.023,1.6843],[1.4034,1.013,0.8944,2.027,1.6917],

[1.3935,1.007,0.8944,2.031,1.6957],[1.39,1.01,0.8918,2.038,1.6955],[1.412,0.995,0.8833,2.025,1.6938],[1.6938,1.002,0.8735,2.032,1.6899]]) #创建数组

data_total = pd.DataFrame(data=value_total,index=date,columns=name)  #转为数据框

print(data_total)  # 输出数据数据

#任务四
import numpy as np

import pandas as pd  # 导入Pandas数据分析库

value_guotai = np.array([1.5284,1.4596,1.3745,1.4034,1.3935,1.39,1.412,1.4164]) #国泰金鑫股票基金2024年8月1日至8日净值数据的数组

date = np.array(["2024-08-01","2024-08-02","2024-08-05","2024-08-06","2024-08-07","2024-08-08","2024-08-09","2024-08-12"]) #交易日数组

series_guotai = pd.Series(data=value_guotai,index=date)  # 创建Series序列series_guotai

data=[1.4596,1.001,0.897,2.051,1.7385];index=["国泰金鑫","中海医疗","华夏优势","富国城镇","上投摩根"] #创建8月2日基金净值的数组

value_0403 = pd.Series(data,index)  # 创建Series序列value_0403

name = np.array(["国泰金鑫","中海医疗","华夏优势","富国城镇","上投摩根"])  #基金名称的数组并且用基金简称

data_3fund_array =  np.array([[1.01,0.8918,2.038],[0.995,0.8833,2.025],[1.002,0.8735,2.032]])#3只基金在2024年8月8日至12日净值的数组

data_3fund = pd.DataFrame(data=data_3fund_array,index=date[5:],columns=name[1:4])  # 创建数据框data_3fund


list_guotai = list(series_guotai)#国泰金鑫8与1日到12日净值数据的序列转为列表

array_0403 = np.array(value_0403) #8月2日5只基金净值的序列转为数组

array_3fund = data_3fund.values  #8月8日到12日3只基金净值的数据框变为数组
print(array_3fund)  # 输出基金数据
列表 48.2
# =============================================================================
# 题目:创建Pandas Series对象
# =============================================================================
# 本任务演示三种不同的Series创建方法,适用于不同的数据来源场景

# ==================== 导入必要的库 ====================
# pandas:Python数据分析的核心库
import pandas as pd
# numpy:Python科学计算的基础库,pandas依赖numpy
import numpy as np

# ==================== 方法1:从Python列表创建Series ====================
# 场景:当你有一系列数值数据需要存储为Series时
# 列表[10, 20, 30, 40, 50]包含5个整数元素
# pd.Series()函数将列表转换为Series对象
# Series会自动为这些元素创建默认的整数索引(0, 1, 2, 3, 4)
s1 = pd.Series([10, 20, 30, 40, 50])
# 结果:一个Series对象,值为[10, 20, 30, 40, 50],索引为[0, 1, 2, 3, 4]

# ==================== 方法2:从字典创建Series ====================
# 场景:当你有键值对数据,且键本身就是有意义的标签时
# 字典的键(股票名称)会成为Series的索引
# 字典的值(股价)会成为Series的值
# name参数指定Series的名称,用于标识这个Series
s2 = pd.Series({
    '贵州茅台': 1850,  # 键'贵州茅台',值1850(股价)
    '五粮液': 220,     # 键'五粮液',值220(股价)
    '招商银行': 45      # 键'招商银行',值45(股价)
}, name='股价')  # 设置Series名称为'股价'
# 结果:一个Series对象,索引为['贵州茅台', '五粮液', '招商银行']
#       值为[1850, 220, 45],名称为'股价'

# ==================== 方法3:从NumPy数组创建Series ====================
# 场景:当你有数值计算的结果需要转换为Series时
# np.random.randn(5)生成5个标准正态分布的随机数(均值0,标准差1)
# 这些随机数可以用于模拟股票收益率等金融数据
s3 = pd.Series(np.random.randn(5))
# 结果:一个Series对象,包含5个随机数,索引为默认的[0, 1, 2, 3, 4]

# ==================== 打印输出Series对象 ====================
print('Series 1 (从列表创建):')
print(s1)  # 输出Series的完整表示:索引、值、数据类型

print('\nSeries 2 (从字典创建):')
print(s2)  # 输出带名称的Series
print(f'索引: {s2.index.tolist()}')  # .index获取索引对象,.tolist()转换为Python列表
# 输出:['贵州茅台', '五粮液', '招商银行']

代码深度解析:

  1. Series的组成结构
    • 索引(index):每个数据点的标签,用于定位和访问数据
    • 值(values):实际存储的数据
    • 名称(name):Series对象的标识(可选)
    • 数据类型(dtype):值的类型(如int64、float64、object等)
  2. 从字典创建的优势
    • 索引自动设置为字典的键,无需手动指定
    • 适合表示有标签的数据(如股票名称到价格的映射)
    • 比从列表创建后设置索引更简洁
  3. Series与NumPy数组的关系
    • Series基于NumPy数组构建
    • Series.values返回底层的NumPy数组
    • Series比NumPy数组多了索引功能

48.3 创建DataFrame

DataFrame是Pandas的二维数据结构,类似于Excel表格或SQL数据库的表。在金融分析中,DataFrame是最常用的数据结构,用于存储和分析多只股票的多指标数据。

列表 48.3
# =============================================================================
# 题目:创建Pandas DataFrame对象
# =============================================================================
# 本任务演示如何从字典创建DataFrame来存储股票数据

# ==================== 从字典创建DataFrame ====================
# 场景:当你的数据是以字典形式组织时,每个键是一个列名,每个值是列数据
# 字典的键('股票代码', '股票名称', '股价', '涨跌幅')将成为DataFrame的列名
# 字典的值都是列表,这些列表的长度必须相同(这里都是3个元素)
data = {
    '股票代码': ['600519.SH', '000858.SZ', '600036.SH'],  # 第一列:股票代码
    '股票名称': ['贵州茅台', '五粮液', '招商银行'],     # 第二列:公司名称
    '股价': [1850.0, 220.5, 45.2],                   # 第三列:股价(浮点数)
    '涨跌幅': [0.05, -0.02, 0.03]                     # 第四列:涨跌幅(浮点数)
}

# pd.DataFrame()函数将字典转换为DataFrame对象
# Pandas会自动:
#   1. 使用字典的键作为列名
#   2. 对齐所有列表的数据(创建3行×4列的表格)
#   3. 自动生成默认的行索引(0, 1, 2)
df = pd.DataFrame(data)

# ==================== 打印DataFrame的基本信息 ====================
print('DataFrame内容:')
print(df)
# 输出格式:
#    股票代码   股票名称     股价  涨跌幅
# 0  600519.SH   贵州茅台  1850.0  0.05
# 1  000858.SZ   五粮液    220.5  -0.02
# 2  600036.SH   招商银行   45.2  0.03
# 左侧的0,1,2是行索引,顶部是列名

# ==================== 查看DataFrame的属性 ====================
print(f'\nDataFrame形状: {df.shape}')  # shape属性返回(行数, 列数)
# 输出:(3, 4) - 表示3行4列的表格
print(f'列名列表: {df.columns.tolist()}')  # columns获取所有列名,tolist()转换为列表
# 输出:['股票代码', '股票名称', '股价', '涨跌幅']

48.4 从NumPy数组创建DataFrame

在科学计算和金融建模中,数据往往以NumPy数组的形式产生(如数值模拟的结果、矩阵运算的结果)。将NumPy数组转换为DataFrame可以添加有意义的标签,使数据更易读和易分析。

列表 48.4
# =============================================================================
# 题目:从NumPy数组创建DataFrame
# =============================================================================
# 本任务演示如何将NumPy数值数组转换为带标签的DataFrame

# ==================== 创建随机NumPy数组 ====================
# np.random.randn(5, 3)生成一个5行×3列的数组
# 5行:5个观测样本(如5个交易日或5只股票)
# 3列:每个样本有3个特征(如开盘价、最高价、最低价)
# 这些数据服从标准正态分布(均值0,标准差1)
arr = np.random.randn(5, 3)
# 结果:一个5×3的NumPy数组,包含随机数值

# ==================== 将NumPy数组转换为DataFrame ====================
# pd.DataFrame()函数可以将NumPy数组转换为DataFrame
# arr参数:要转换的NumPy数组(数据来源)
# columns参数:指定DataFrame的列名(列表形式)
# index参数:指定DataFrame的行标签(列表形式)
df_random = pd.DataFrame(
    arr,                           # 数据来源:5×3的随机数组
    columns=['特征1', '特征2', '特征3'],  # 列名:为3列分别命名
    index=['样本1', '样本2', '样本3', '样本4', '样本5']  # 行标签:为5行分别命名
)
# 结果:一个5×3的DataFrame,行标签为"样本1"到"样本5",列名为"特征1"到"特征3"

# ==================== 打印DataFrame ====================
print('从NumPy数组创建的DataFrame:')
print(df_random)
# 输出格式:
#             特征1      特征2      特征3
# 样本1  随机值1   随机值2   随机值3
# 样本2  随机值1   随机值2   随机值3
# ...(共5行)

48.5 从列表的列表创建DataFrame

当数据以嵌套列表的形式组织时(例如从CSV文件读取的数据,或从API获取的JSON数据),也可以直接创建DataFrame。

列表 48.5
# =============================================================================
# 题目:从列表的列表创建DataFrame
# =============================================================================
# 本任务演示如何将嵌套列表转换为DataFrame

# ==================== 准备嵌套列表数据 ====================
# 场景:当你有多个记录,每个记录包含多个字段时
# 外层列表包含3个元素(3条股票记录)
# 每个元素是一个列表,包含[名称, 价格, 涨跌幅]三个字段
data_list = [
    ['贵州茅台', 1850.0, 0.05],    # 第1条记录
    ['五粮液', 220.5, -0.02],      # 第2条记录
    ['招商银行', 45.2, 0.03]      # 第3条记录
]
# data_list是一个"列表的列表"结构

# ==================== 从列表的列表创建DataFrame ====================
# pd.DataFrame()函数可以接受嵌套列表作为输入
# data_list参数:数据源(嵌套列表)
# columns参数:指定列名,为每列数据赋予有意义的名称
#   - '名称':第一列数据(股票名称)
#   - '价格':第二列数据(股价)
#   - '涨跌幅':第三列数据(涨跌百分比)
df_from_list = pd.DataFrame(
    data_list,                    # 数据:嵌套列表
    columns=['名称', '价格', '涨跌幅']  # 列名:指定3个列的名称
)
# Pandas会自动将嵌套列表的每个子列表对应到一行
# 子列表的第0个元素对应第1列,第1个元素对应第2列,以此类推

# ==================== 打印DataFrame ====================
print('从列表的列表创建的DataFrame:')
print(df_from_list)
# 输出格式:
#      名称     价格  涨跌幅
# 0  贵州茅台  1850.0  0.05
# 1  五粮液    220.5  -0.02
# 2  招商银行   45.2  0.03

48.6 设置DataFrame的索引

索引(Index)是Pandas数据结构的重要特性,它为每行数据提供了一个有意义的标识。在金融时间序列分析中,通常将日期设置为索引,以便进行时间序列操作(如按日期切片、重采样等)。

列表 48.6
# =============================================================================
# 题目:设置DataFrame的行索引
# =============================================================================
# 本任务演示如何为DataFrame设置有意义的行标签

# ==================== 创建示例DataFrame ====================
# 创建一个简单的DataFrame用于演示
df = pd.DataFrame({
    '价格': [10, 20, 30, 40, 50],        # 第1列:价格数据
    '销量': [100, 200, 150, 300, 250]    # 第2列:销量数据
})
# 默认会创建整数索引0, 1, 2, 3, 4

# ==================== 生成日期序列作为索引 ====================
# pd.date_range()函数生成日期序列(DatetimeIndex对象)
# '2024-01-01':起始日期
# periods=5:生成5个日期
# 默认频率是'D'(每天),也可以指定'B'(工作日)、'M'(月)等
dates = pd.date_range('2024-01-01', periods=5)
# 结果:DatetimeIndex(['2024-01-01', '2024-01-02', ..., '2024-01-05'])

# ==================== 将日期设置为DataFrame的索引 ====================
# set_index()方法将某列(或外部数据)设置为行索引
# dates参数:使用前面生成的日期序列作为新索引
# 原来的整数索引(0, 1, 2, 3, 4)会被替换
df_indexed = df.set_index(dates)
# 结果:DataFrame的行索引变成了日期,而不是数字

# ==================== 打印带日期索引的DataFrame ====================
print('带日期索引的DataFrame:')
print(df_indexed)
# 输出格式:
#             价格  销量
# 2024-01-01   10  100
# 2024-01-02   20  200
# 2024-01-03   30  150
# ...(共5行)
# 左侧是日期索引,不再是0, 1, 2...

# ==================== 索引的好处 ====================
# 现在可以使用日期来选择数据,例如:
# df_indexed.loc['2024-01-01']  # 获取特定日期的数据
# df_indexed.loc['2024-01-01':'2024-01-03']  # 获取日期范围的数据
# 这比使用整数位置(如df.iloc[0:3])更直观、更不容易出错